package com.xncoding.pos.async;

import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.task.TaskDecorator;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import java.util.Arrays;
import java.util.concurrent.*;

/**
 * 线程池配置
 */
@Configuration
@EnableAsync //支持注解式异步方法
@Slf4j
public class ThreadPoolTaskConfig {


    // AbortPolicy：默认策略。直接抛出 RejectedExecutionException
    // DiscardPolicy：直接丢弃掉被拒绝的任务，且不会抛出任何异常
    // DiscardOldestPolicy：丢弃掉队列中的队头元素（也就是最早在队列里的任务），然后重新执行 提交该任务 的操作
    // CallerRunsPolicy：由主线程自己来执行这个任务，该机制将减慢新任务的提交


    // 对同一个接口，可能会有几种不同的实现类，而默认只会采取其中一种。这种情况下 @Primary 的作用就出来了。
    // 默认会注入@Primary配置的组件。

    /**
     * 默认线程池线程池(线程数满的时候重试添加当前的任务)
     *
     * @return Executor
     */
    @Bean
    @Primary
    public ThreadPoolTaskExecutor defaultThreadPool() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        //核心线程数目
        executor.setCorePoolSize(16);
        //指定最大线程数
        executor.setMaxPoolSize(64);
        //队列中最大的数目
        executor.setQueueCapacity(16);
        //线程名称前缀
        executor.setThreadNamePrefix("配置的线程池——");
        //rejection-policy：当pool已经达到max size的时候，如何处理新任务
        //CALLER_RUNS：不在新线程中执行任务，而是由调用者所在的线程来执行
        //对拒绝task的处理策略
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        //线程空闲后的最大存活时间
        executor.setKeepAliveSeconds(60);

        // 绑定全局异常处理器（关键步骤）
        // executor.setTaskDecorator(asyncGlobalExceptionHandler());
        //加载
        executor.initialize();
        return executor;
    }

    // @Bean
    // public TaskDecorator asyncGlobalExceptionHandler() {
    //     // 匿名实现类：捕获异常并输出关键信息
    //     return (exception, method, params) -> {
    //         log.error("异步任务失败：方法[{}]，参数[{}]",
    //                 method.getName(), Arrays.toString(params), exception);
    //         // 统一告警（无需在每个方法重复写）
    //         sendDingAlarm("全局异步异常：" + exception.getMessage());
    //     };
    // }

    /**
     * spring里的线程池
     * 拒绝策略: 当线程池满的时候就抛弃旧的任务
     *
     * @return
     */
    @Bean
    public ThreadPoolTaskExecutor taskExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        //核心线程数目
        executor.setCorePoolSize(16);
        //指定最大线程数
        executor.setMaxPoolSize(64);
        //队列中最大的数目
        executor.setQueueCapacity(16);
        //线程名称前缀
        executor.setThreadNamePrefix("配置的线程池副的_");
        //rejection-policy：当pool已经达到max size的时候，如何处理新任务
        //CALLER_RUNS：不在新线程中执行任务，而是由调用者所在的线程来执行
        //对拒绝task的处理策略
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardOldestPolicy());
        //线程空闲后的最大存活时间
        executor.setKeepAliveSeconds(60);
        //加载
        executor.initialize();
        return executor;
    }

    private static int corePoolSize = Runtime.getRuntime().availableProcessors();


    /**
     * JDK里的线程池
     *
     * @return
     */
    @Bean(name = "executorService")
    public ExecutorService executorService() {
        // 获取Java虚拟机的可用的处理器数，最佳线程个数，处理器数*2。根据实际情况调整
        // int curSystemThreads = Runtime.getRuntime().availableProcessors() * 2;
        // log.info("------------系统可用线程池个数：" + curSystemThreads);
        // 创建线程池

        // ExecutorService executor = Executors.newFixedThreadPool(10);
        //JDK创建线程池  调整队列数 拒绝服务

        ThreadPoolExecutor executor = new ThreadPoolExecutor(corePoolSize, corePoolSize + 1, 10l, TimeUnit.SECONDS,
                new LinkedBlockingQueue<>(10));

        // executor = new ThreadPoolExecutor(0, 10,
        //         0, TimeUnit.MICROSECONDS, new ArrayBlockingQueue<Runnable>(5));

        // 设置线程池的拒绝策略
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());

        return executor;
    }


    // ThreadPoolExecutor.AbortPolicy:丢弃任务并抛出RejectedExecutionException异常。
    // ThreadPoolExecutor.DiscardPolicy：也是丢弃任务，但是不抛出异常。
    // ThreadPoolExecutor.DiscardOldestPolicy：丢弃队列最前面的任务，然后重新尝试执行任务（重复此过程）
    // ThreadPoolExecutor.CallerRunsPolicy：由调用线程处理该任务

    // class Handler implements RejectedExecutionHandler {
    //
    //     @Override
    //     public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
    //         System.out.println("线程被拒绝了" + r.toString());
    //     }
    // }
}
